package net.lab1024.sa.admin.module.business.aps.domain.optaplanner;

import lombok.Data;
import lombok.NoArgsConstructor;
import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty;
import org.optaplanner.core.api.domain.solution.PlanningScore;
import org.optaplanner.core.api.domain.solution.PlanningSolution;
import org.optaplanner.core.api.domain.solution.ProblemFactCollectionProperty;
import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;

import java.util.List;

/**
 * OptaPlanner排程解决方案
 * APS排程优化的解决方案类
 *
 * @Author 1024创新实验室
 * @Date 2025-01-28
 * @Wechat zhuoda1024
 * @Email lab1024@163.com
 * @Copyright <a href="https://1024lab.net">1024创新实验室</a>
 */
@Data
@NoArgsConstructor
@PlanningSolution
public class ScheduleSolution {

    /**
     * 问题事实：可用资源列表
     */
    @ProblemFactCollectionProperty
    @ValueRangeProvider(id = "resourceRange")
    private List<Resource> resourceList;

    /**
     * 问题事实：可用时间槽列表
     */
    @ProblemFactCollectionProperty
    @ValueRangeProvider(id = "timeSlotRange")
    private List<TimeSlot> timeSlotList;

    /**
     * 规划实体：待排程任务列表
     */
    @PlanningEntityCollectionProperty
    private List<Task> taskList;

    /**
     * 规划分数
     */
    @PlanningScore
    private HardSoftScore score;

    /**
     * 解决方案名称
     */
    private String solutionName;

    /**
     * 排程开始时间
     */
    private String scheduleStartTime;

    /**
     * 排程结束时间
     */
    private String scheduleEndTime;

    /**
     * 构造函数
     */
    public ScheduleSolution(List<Resource> resourceList, List<TimeSlot> timeSlotList, 
                           List<Task> taskList, String solutionName) {
        this.resourceList = resourceList;
        this.timeSlotList = timeSlotList;
        this.taskList = taskList;
        this.solutionName = solutionName;
    }

    /**
     * 获取已分配任务数量
     */
    public int getAssignedTaskCount() {
        if (taskList == null) {
            return 0;
        }
        return (int) taskList.stream()
                .filter(task -> task.getAssignedResource() != null && task.getStartTimeSlot() != null)
                .count();
    }

    /**
     * 获取未分配任务数量
     */
    public int getUnassignedTaskCount() {
        if (taskList == null) {
            return 0;
        }
        return taskList.size() - getAssignedTaskCount();
    }

    /**
     * 获取总任务数量
     */
    public int getTotalTaskCount() {
        return taskList == null ? 0 : taskList.size();
    }

    /**
     * 获取资源利用率
     */
    public double getResourceUtilization() {
        if (resourceList == null || resourceList.isEmpty() || taskList == null) {
            return 0.0;
        }
        
        int totalCapacity = resourceList.stream()
                .mapToInt(Resource::getCapacity)
                .sum();
        
        int usedCapacity = (int) taskList.stream()
                .filter(task -> task.getAssignedResource() != null)
                .count();
        
        return totalCapacity > 0 ? (double) usedCapacity / totalCapacity : 0.0;
    }

    /**
     * 检查解决方案是否可行
     */
    public boolean isFeasible() {
        return score != null && score.isFeasible();
    }

    /**
     * 获取解决方案摘要信息
     */
    public String getSolutionSummary() {
        return String.format("解决方案: %s | 总任务: %d | 已分配: %d | 未分配: %d | 资源利用率: %.2f%% | 分数: %s",
                solutionName != null ? solutionName : "未命名",
                getTotalTaskCount(),
                getAssignedTaskCount(),
                getUnassignedTaskCount(),
                getResourceUtilization() * 100,
                score != null ? score.toString() : "未计算");
    }

    /**
     * 克隆解决方案（用于OptaPlanner内部）
     */
    public ScheduleSolution clone() {
        ScheduleSolution clone = new ScheduleSolution();
        clone.resourceList = this.resourceList;
        clone.timeSlotList = this.timeSlotList;
        clone.taskList = this.taskList;
        clone.score = this.score;
        clone.solutionName = this.solutionName;
        clone.scheduleStartTime = this.scheduleStartTime;
        clone.scheduleEndTime = this.scheduleEndTime;
        return clone;
    }
}